#ifndef ADDOBJETBASE_H
#define ADDOBJETBASE_H 1

#include "FlotMessage.h"

#include <map>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

class FlotMessage;

/** @brief Classe de base pour tous les objets définis dans le projet.
 *
 * Prototype de classe qui devrait être une classe de base pour toutes
 * les classes du projet. Le but est de définir pour chaque objet un
 * type, qui peut être affiché par n'importe quelle méthode.
 *
 * @author Johan "Solo" Luisier
 */
class ADDObjetBase
{
public:
    /** @brief Constructeur usuel.
     *
     * Ce constructeur initialise le champ TypeObjet et l'instance de
     * FlotMessage.
     *
     * @param[in] typeObjet nom (type) de l'objet.
     */
    ADDObjetBase( const std::string& typeObjet );
    /** @brief Destructeur, déclaré virtuel pour assurer une séquence de
     * destruction propre.
     *
     * Le destructeur n'a rien de spécial à faire.
     */
    ~ADDObjetBase();
    /** @brief Opérateur d'affectation.
     *
     * L'opérateur d'affectation permet de copier une instance dans l'instance
     * courante.
     *
     * @param[in] obj instance de ADDObjetBase à dupliquer.
     *
     * @return une référence sur l'instance courante.
     */
    ADDObjetBase& operator=( const ADDObjetBase& obj );
    /** @brief Accesseur pour TypeObjet.
     *
     * Cette méthode permet d'accéder au type de l'objet.
     *
     * @return une référence constante sur TypeObjet.
     */
    const std::string& typeObjet() const;
    /** @brief Mutateur pour TypeObjet.
     *
     * Cette méthode permet de modifier la valeur de TypeObjet.
     *
     * @param[in] typeObjet nouvelle valeur de TypeObjet.
     */
    void setTypeObjet( const std::string& typeObjet );
    /** @brief Méthode permettant de modifier le niveau courant en ERR.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur ERR.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& error() const;
    /** @brief Méthode permettant de modifier le niveau courant en WARN.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur WARN.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& warning() const;
    /** @brief Méthode permettant de modifier le niveau courant en BLANK.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur BLANK.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& blank() const;
    /** @brief Méthode permettant de modifier le niveau courant en INFO.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur INFO.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& info() const;
    /** @brief Méthode permettant de modifier le niveau courant en FUNC.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur FUNC.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& func() const;
    /** @brief Méthode permettant de modifier le niveau courant en LINFO.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur LINFO.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& linfo() const;
    /** @brief Méthode permettant de modifier le niveau courant en LFUNC.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur LFUNC.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& lfunc() const;
    /** @brief Méthode permettant de modifier le niveau courant en DEBUG.
     *
     * Cette méthode permet de d'accéder à SortieStd après avoir mis le niveau
     * de sortie courant de SortieStd sur DEBUG.
     *
     * @return un référence sur SortieStd.
     */
    FlotMessage& debug() const;
protected:
    /**
     * Instance de FlotMessage utilisée pour réaliser l'affichage dans
     * le terminal des différents messages.
     *
     * Est déclaré mutable pour pouvoir être modifié même dans les
     * méthodes const.
     */
    mutable FlotMessage SortieStd;
    /** @brief Méthode permettant de changer le niveau de sortie.
     *
     * Cette méthode permet d'ajouter un niveau de sortie sur la pile. Si ce
     * nouveau niveau est différent du précédent, alors on change
     * automatiquement le niveau de référence de SortieStd.

     * @param[in] level pointeur sur la valeur à ajouter.
     */
    void empileNiveau( const DebugLevelType* level ) const;
    /** @brief Méthode permettant de revenir au niveau de sortie précédent.
     *
     * Cette mérhode permet de vider la pile d'un élément. Le niveau de
     * référence de SortieStd est automatiquement changé si nécessaire.
     */
    void depileNiveau() const;
private:
    /** @brief Constructeur par défaut.
     *
     * Ce constructeur ne peut pas être appelé, ce qui force l'utilisateur à
     * spécifier le type d'objet que l'on construit.
     */
    ADDObjetBase();
    /**
     * Type de l'objet, en fait il s'agit du nom de la classe.
     */
    std::string TypeObjet;
    /**
     * Pile constituée des niveaux de sorties successifs. Le niveau
     * actif set toujours le dernier (\c top()). La pile est augmentée de
     * manière intellignente : si on veut ajouter un élément égal au
     * précédent, alors on ajoute en fait rien.
     */
    mutable stack< const DebugLevelType* > Historique;
    /**
     * Pile permettant de gérer quand les éléments de Historique doivent
     * être dépilés. Si l'ajout dans Historique n'a pas lieu car le même
     * élément est déjà présent, alors on empile \e true dans
     * IdemPrecedent, et la valeur ne sera pas dépilée ensuite.
     */
    mutable stack< bool, vector< bool > > IdemPrecedent;
};

#endif // ADDOBJETBASE_H
